package woaini.wind.bot.command.qylc.app.api;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.gitlab4j.api.GitLabApi;
import org.gitlab4j.api.GitLabApiException;
import org.gitlab4j.api.models.*;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Component;
import woaini.wind.bot.command.qylc.app.api.config.TagNameConfig;
import woaini.wind.bot.core.bind.service.BotUserConfigService;
import woaini.wind.bot.core.command.ICmd;
import woaini.wind.bot.core.command.anno.CmdParams;
import woaini.wind.bot.core.command.anno.SubCmd;
import woaini.wind.bot.core.event.segment.Messages;
import woaini.wind.bot.core.exception.BotAssertTool;
import woaini.wind.bot.core.exception.enums.BotExceptionType;
import woaini.wind.bot.core.json.JSONResult;
import woaini.wind.bot.core.session.Session;
import woaini.wind.bot.core.utils.TokenCacheTool;
import woaini.wind.bot.botConfig.qylc.QylcAppConfig;
import woaini.wind.bot.gitlab.service.GitLabWebHookHandler;
import woaini.wind.bot.job.qylc.QYLCEarlyWarningJob;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

/**
 * 公司相关
 *
 * @see QylcCmd
 * @author yefeng {@code @Date} 2023-05-16 16:50:39
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class QylcCmd implements ICmd {

  private final BotUserConfigService botUserConfigService;
  private final GitLabApi gitLabApi;

  private static final Map<String, TagNameConfig> TAG_NAME_CONFIGMAP;

  static {
    TAG_NAME_CONFIGMAP = new HashMap<>();
    TAG_NAME_CONFIGMAP.put("hmall", new TagNameConfig("mall", "hmall", "hmall-prod"));
    TAG_NAME_CONFIGMAP.put("hmallpage", new TagNameConfig("mall", "hmallpage", "main"));
    TAG_NAME_CONFIGMAP.put("marketing", new TagNameConfig("mall", "Marketing", "prod"));
  }

  @Override
  public String masterCmdName() {
    return "公司";
  }

  @Override
  public String description() {
    return "公司内部相关接口";
  }

  @Override
  public boolean auth() {
    return true;
  }

  @SubCmd(value = "打卡", auth = true,enabled = false)
  public void clockIn(
      Session session,
      @CmdParams(value = "down", description = "是否下班打卡", defaultValue = "false") Boolean down,
      @CmdParams(value = "u", description = "登录手机号,默认为本机") String loginName) {

    // 获取配置
    QylcAppConfig qylcAppConfig = this.getQylcAppConfig(session, loginName);

    String tokenKey = QylcAppConfig.CONFIG_KEY + ":" + qylcAppConfig.getLoginName();
    String jwt =
        TokenCacheTool.getAndLoadWithKey(
            tokenKey,
            (token) -> QylcApi.verifyActivityStatistics(qylcAppConfig,token),
            () -> {
              JSONResult login = QylcApi.login(qylcAppConfig);
              return login.getPathValue("$.data.jwt").toString();
            });
    JSONResult schedulingUserResult = QylcApi.schedulingUserList(qylcAppConfig, jwt);
    String schedulingId = null;
    schedulingId = (String) schedulingUserResult.getPathValue("$.data[0].schedulingId");
    if (StrUtil.isEmpty(schedulingId)) {
      JSONResult clockInTypeResult = QylcApi.getClockInType(qylcAppConfig, jwt);
      schedulingId = (String) clockInTypeResult.getPathValue("$.data.schedulingId");
    }
    BotAssertTool.isActualTrue(
        StrUtil.isEmpty(schedulingId), BotExceptionType.BOT_SERVICE_PARAMS, "排班记录不存在,打卡失败!!!");

    QylcApi.randomLocation();
    QylcApi.verifyClockInLog(qylcAppConfig, jwt, schedulingId, !down);
    QylcApi.saveClockInLog(qylcAppConfig, jwt, schedulingId, !down);
    session.replyMessage(Messages.builder().text((down ? "下" : "上") + "班打卡成功!!"));
  }

  @Nullable
  private QylcAppConfig getQylcAppConfig(Session session, String loginName) {
    QylcAppConfig qylcAppConfig = null;
    if (StrUtil.isEmpty(loginName)) {
      qylcAppConfig = session.getCurrentUserConfig(QylcAppConfig.CONFIG_KEY, QylcAppConfig.class);
    } else {
      qylcAppConfig =
          botUserConfigService.getBotUserLocalConfig(
              QylcAppConfig.CONFIG_KEY, loginName, QylcAppConfig.class);
      BotAssertTool.isActualTrue(
          qylcAppConfig == null,
          BotExceptionType.BOT_SERVICE,
          "不存在配置:[{}],key:{}",
          QylcAppConfig.CONFIG_KEY,
          loginName);
    }
    BotAssertTool.isActualTrue(
        qylcAppConfig == null,
        BotExceptionType.BOT_SERVICE,
        "不存在配置:[{}]",
        QylcAppConfig.CONFIG_KEY);
    return qylcAppConfig;
  }

  @SubCmd(value = "菜单", auth = true,enabled = false)
  public void foodMenu(Session session) {
    QylcAppConfig qylcAppConfig = this.getQylcAppConfig(session, null);
    String tokenKey = STR."\{QylcAppConfig.CONFIG_KEY}:\{qylcAppConfig.getLoginName()}";
    String jwt =
      TokenCacheTool.getAndLoadWithKey(
        tokenKey,
        (token) -> QylcApi.verifyActivityStatistics(qylcAppConfig,token),
        () -> {
          JSONResult login = QylcApi.login(qylcAppConfig);
          return login.getPathValue("$.data.jwt").toString();
        });
    JSONResult jsonResult = QylcApi.foodMenu(qylcAppConfig, jwt);

    StringBuilder stringBuilder = new StringBuilder();

    String yearWeek = jsonResult.getPathValue("$.data.yearWeek").toString();
    stringBuilder.append("本周周次:").append(yearWeek).append("\n");
    //时间段
    String startTime = jsonResult.getPathValue("$.data.startTime").toString();
    String endTime = jsonResult.getPathValue("$.data.endTime").toString();
    stringBuilder.append("时间段:").append(startTime).append("到").append(endTime).append("\n");


    String image = jsonResult.getPathValue("$.data.image").toString();

    Messages messages = Messages.builder().text(stringBuilder.toString()).image(image);
    session.replyMessage(messages);
  }

  @SubCmd(value = "标签创建",description = "快速进行版本打包处理",auth = true)
  public void tagCreate(Session session,
                        @CmdParams(value = "n", description = "配置名称(hmall,hmallpage)",required = true) String name,
                        @CmdParams(value = "t", description = "tag",required = true) String tag,
                        @CmdParams(value = "m", description = "简易描述",defaultValue = "版本发布") String message
                        ){

    //获取标签配置
    TagNameConfig tagNameConfig = TAG_NAME_CONFIGMAP.get(name);
    BotAssertTool.isActualTrue(tagNameConfig == null,
      BotExceptionType.BOT_SERVICE, "不存在配置:[{}]", name);
    //进行标签创建
    Project project = getProject(tagNameConfig);
    try {
      Tag tag1 = gitLabApi.getTagsApi().createTag(project.getId(), tag, tagNameConfig.getBranch(), message,message);
      session.replyMessage(Messages.builder().text(STR."创建成功:\{tag1.getName()}"));
      GitLabWebHookHandler.addHookTag(tag);
      session.replyMessage(Messages.builder().text(STR."添加流水线监听成功:\{tag1.getName()}"));
    } catch (GitLabApiException e) {
      log.error("创建标签异常",e);
      session.replyMessage(Messages.builder().text(STR."创建失败:\{e.getMessage()}"));
    }
  }

  @SubCmd(value = "任务触发",description = "建议提示打包通过后调用 直接触发推送",auth = true)
  public void pipelineTrigger(Session session, @CmdParams(value = "n", description = "配置名称(hmall,hmallpage)",required = true) String name,
                        @CmdParams(value = "t", description = "指定标签",required = true) String tag,
                        @CmdParams(value = "e", description = "指定推送平台 例如kns,hgs,qylw") String env,
                        @CmdParams(value = "s", description = "指定推送服务,名称,号隔开 service,open") String services
  ){
    //获取标签配置
    TagNameConfig tagNameConfig = TAG_NAME_CONFIGMAP.get(name);
    BotAssertTool.isActualTrue(tagNameConfig == null,
      BotExceptionType.BOT_SERVICE, "不存在配置:[{}]", name);
    //进行标签创建
    Project project = getProject(tagNameConfig);

    try {
      PipelineFilter pipelineFilter = new PipelineFilter();
      pipelineFilter.withRef(tag);
      List<Pipeline> pipelines = gitLabApi.getPipelineApi().getPipelines(project.getId(), pipelineFilter);
      //获取流水线任务
      List<Job> jobsForPipeline = gitLabApi.getJobApi().getJobsForPipeline(project.getId(), pipelines.get(0).getId());
      Stream<Job> stream = jobsForPipeline.stream();
      //过滤任务已经成功的
      stream = stream.filter(d->!d.getName().contains("success"));

      if (StrUtil.isNotEmpty(env)){
        stream = stream.filter(d->d.getName().startsWith(env));
      }
      if (StrUtil.isNotEmpty(services)){
        stream = stream.filter(d->{
          List<String> split = StrUtil.split(services, ",");
          for (String service : split) {
            if (d.getName().contains(service)){
              return true;
            }
          }
          return false;
        });
      }
      jobsForPipeline = stream.toList();
      //添加监听
      GitLabWebHookHandler.addHookTag(tag);
      //进行触发任务
      for (Job job : jobsForPipeline) {
        gitLabApi.getJobApi().playJob(project.getId(), job.getId());
      }
      session.replyMessage(Messages.builder().text(STR."流水线任务触发成功:\{tag}"));
    } catch (GitLabApiException e) {
      BotAssertTool.throwServiceException("流水线任务触发失败:[{}]", tag);
    }

  }

  @SubCmd(value = "任务信息",description = "获取任务执行的信息",auth = true)
  public void pipelineJobInfo(Session session, @CmdParams(value = "n", description = "配置名称(hmall,hmallpage)",required =
                            true) String name,
                              @CmdParams(value = "t", description = "标签",required = true) String tag,
                              @CmdParams(value = "e", description = "指定查找平台 例如kns,hgs,qylw") String env,
                              @CmdParams(value = "s", description = "指定查找服务,名称,号隔开 service,open") String services,
                              @CmdParams(value = "S", description = "是否仅成功的",defaultValue = "false") Boolean success
  ){

    //获取标签配置
    TagNameConfig tagNameConfig = TAG_NAME_CONFIGMAP.get(name);
    BotAssertTool.isActualTrue(tagNameConfig == null,
      BotExceptionType.BOT_SERVICE, "不存在配置:[{}]", name);
    //进行标签创建
    Project project = getProject(tagNameConfig);
    try {

      PipelineFilter pipelineFilter = new PipelineFilter();
      pipelineFilter.withRef(tag);
      List<Pipeline> pipelines = gitLabApi.getPipelineApi().getPipelines(project.getId(), pipelineFilter);

      //获取流水线任务
      List<Job> jobsForPipeline = gitLabApi.getJobApi().getJobsForPipeline(project.getId(), pipelines.get(0).getId());
      Stream<Job> stream = jobsForPipeline.stream();

      if (ObjectUtil.isNotEmpty(success)){
        //过滤任务已经成功的
        stream = stream.filter(d->d.getStatus() == JobStatus.SUCCESS);
      }
      if (StrUtil.isNotEmpty(env)){
        stream = stream.filter(d->d.getName().startsWith(env));
      }
      if (StrUtil.isNotEmpty(services)){
        stream = stream.filter(d->{
          List<String> split = StrUtil.split(services, ",");
          for (String service : split) {
            if (d.getName().contains(service)){
              return true;
            }
          }
          return false;
        });
      }
      jobsForPipeline = stream.toList();
      //进行任务情况返回
      StringBuilder stringBuilder = new StringBuilder();
      for (Job job : jobsForPipeline) {
        String itemJobInfo = STR."\{job.getName()} : \{job.getStatus()}\n";
        stringBuilder.append(itemJobInfo);
      }
      session.replyMessage(Messages.builder().text(stringBuilder.toString()));
    } catch (GitLabApiException e) {
      BotAssertTool.throwServiceException("流水线任务查询失败:[{}]", tag);
    }
  }

  private Project getProject(TagNameConfig tagNameConfig) {
    try {
      Project project = gitLabApi.getProjectApi().getProject(tagNameConfig.getGroup(), tagNameConfig.getProject());
      BotAssertTool.isActualTrue(project == null,BotExceptionType.BOT_SERVICE,"项目不存在");
      return project;
    } catch (GitLabApiException e) {
      log.error("项目获取异常",e);
      BotAssertTool.throwServiceException("项目获取异常!!");
    }
    return null;
  }


  @SubCmd(value = "关闭预警",description = "临时关闭预警",auth = true)
  public void stopWarning(Session session,
                              @CmdParams(value = "e", description = "指定查找平台 例如kns,hgs,qylw",required = true) String env,
                              @CmdParams(value = "m", description = "指定屏蔽分钟",required = true) Long minutes
  ){
    //进行屏蔽
    QYLCEarlyWarningJob.timedCache.put(env,env, DateUnit.MINUTE.getMillis() * minutes);
    session.replyMessage(Messages.builder().text(STR."\{env}预警屏蔽成功,屏蔽时间:\{minutes}分钟"));
  }

  @SubCmd(value = "启动预警",description = "启动预警",auth = true)
  public void stopWarning(Session session,
                          @CmdParams(value = "e", description = "指定查找平台 例如kns,hgs,qylw",required = true) String env
  ){
    //进行屏蔽
    QYLCEarlyWarningJob.timedCache.remove(env);
    session.replyMessage(Messages.builder().text(STR."\{env}预警屏蔽解除成功"));
  }
}
